﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WcfGeebaServer.Users;
using WcfGeebaServer.DBDAL;
using System.Runtime.Serialization;
using WcfGeebaServer.Logging;

namespace WcfGeebaServer.ContentManage
{
    [Serializable]
    public class GSubForum
    {
        #region Fields

        private string topic;

        #endregion

        #region DataMembers

        public string Topic
        {
            get { return topic; }
            private set { topic = value; }
        }
        
        #endregion

        #region Ctors

        public GSubForum(string topic)
        {
            this.Topic = topic;
        }

        #endregion

        #region Methods

        public override int GetHashCode()
        {
            return this.Topic.GetHashCode();
        }

        public override bool Equals(Object obj)
        {
            if (obj == null)
            {
                return false;
            }

            GSubForum sf = obj as GSubForum;
            if ((Object)sf == null)
            {
                return false;
            }

            return this.Topic.Equals(sf.Topic);
        }

        public List<GThread> getThreads()
        {
            return SubForumDA.GetSubForumDA().GetThreads(this);
        }

        public int publish(GThread newMessage) 
        {
            Member member = GForum.GetForum().GetMember(newMessage.publishedBy.Username);
            if (!GForum.GetForum().Policy.CanPublishMessage(member, this, newMessage))
            {
                return -1;
            }

            int id = ThreadDA.GetThreadDA().AddThread(newMessage, this);
            //MemberDA.getMemberDA().incThreadCount(newMessage.publishedBy);
            GLogger.log("A new thread(" + id + ") was published by " + newMessage.publishedBy.Username + ":\n" +
                        "Subject: " + newMessage.Subject);
            return id;
        }

        public bool addInitialMemberAsModerator(Member member)
        {
            bool res = SubForumDA.GetSubForumDA().AddModerator(this, member, new ModeratorInfo(DateTime.Now));
            if (res)
            {
                GLogger.log("Added member " + member.Username + " as the first moderator of \"" + this.topic + "\"");
            }
            else
            {
                GLogger.error("Problem adding member " + member.Username + " as the first moderator of \"" + this.topic + "\"", null);
            }
            return res;
        }

        public bool addMemberAsModerator(Member member)
        {
            if (!GForum.GetForum().Policy.CanAddModerator(member, this))
            {
                return false;
            }
            bool res = SubForumDA.GetSubForumDA().AddModerator(this, member, new ModeratorInfo(DateTime.Now));
            if (res)
            {
                GLogger.log("Added member " + member.Username + " as a moderator of \"" + this.topic + "\"");
            }
            else
            {
                GLogger.error("Problem adding member " + member.Username + " as a moderator of \"" + this.topic + "\"", null);
            }
            return res;
        }

        public bool removeModerators()
        {
            bool res = SubForumDA.GetSubForumDA().RemoveModerators(this.topic);
            if (res)
            {
                GLogger.log("All moderators were removed from subforum " + this.topic);
            }
            else
            {
                GLogger.error("Error removing moderators from subforum " + this.topic, null);
            }
            return res;
        }

        public bool removeMemberFromModerators(Member member)
        {
            SubForumDA sfda = SubForumDA.GetSubForumDA();
            if (!GForum.GetForum().Policy.CanRemoveModerator(member, this))
            {
                return false;
            } // removed by gili: when replacing when only 1 moderator will fail!
            bool res = sfda.RemoveModerator(this, member);
            if (res)
            {
                GLogger.log("Member " + member.Username + " has been successfully removed from \"" + this.topic + "\" subforum's list of moderators");
            }
            else
            {
                GLogger.error("Problem removing " + member.Username + " from moderators", null);
            }
            return res;
        }

        public List<KeyValuePair<Member,ModeratorInfo>> getModerators()
        {
            return SubForumDA.GetSubForumDA().GetModerators(this);
        }

        public bool ContainsModerator(Member member)
        {
            foreach (KeyValuePair<Member, ModeratorInfo> m in this.getModerators())
            {
                if (m.Key.Equals(member))
                {
                    return true;
                }
            }
            return false;
        }

        public bool RemoveThread(Member requestingUser, int threadID)
        {
            GThread thread = this.GetThread(threadID);
            if (thread == null)
            {
                return true;
            }
            if (GForum.GetForum().Policy.CanDeleteThread(thread, requestingUser, this))
            {
                GLogger.log("User " + requestingUser.Username + " is removing thread " + thread.Id);
                return this.RemoveThread(thread);
            }
            return false;
        }

        public bool RemoveThread(GThread thread)
        {
            bool res = true;
            List<GPost> posts = thread.getPosts();
            for (int i = 0; i < posts.Count; i++ )
            {
                res &= thread.removePost(posts[i]);
            }
            if (res)
            {
                res = ThreadDA.GetThreadDA().RemoveThread(thread, this);
                if (res)
                {
                    //MemberDA.getMemberDA().decThreadCount(thread.publishedBy);
                    GLogger.log("Removed thread id=" + thread.Id);
                }
                else
                {
                    GLogger.error("Problem removing thread id=" + thread.Id, null);
                }
                return res;
            }
            return false;
        }

        public bool RemoveThread(int threadID)
        {
            List<GThread> threadList = SubForumDA.GetSubForumDA().GetThreads(this);
            int index = threadList.IndexOf(new GThread(threadID, "", "", null));
            if (index < 0)
            {
                return false;
            }
            GThread thread = threadList[index];
            return this.RemoveThread(thread);
        }

        public bool ReplaceModerator(Member oldModerator, Member newModerator)
        {
            // check if can replace, add moderator and remove moderator,
            // and short circuit and return false if any of the methods returns false
            return GForum.GetForum().Policy.CanReplaceModerator(oldModerator, newModerator, this) &&
                   this.addMemberAsModerator(newModerator) &&
                   this.removeMemberFromModerators(oldModerator);
        }

        public int GetThreadCount()
        {
            return SubForumDA.GetSubForumDA().getMessagesCount(this);
        }

        public GThread GetThread(int threadId)
        {
            return ThreadDA.GetThreadDA().GetThread(threadId, this);
        }

        public bool IsModerator(string username)
        {
            Member mem = MemberDA.getMemberDA().GetMember(username);
            if (mem != null)
            {
                List<KeyValuePair<Member, ModeratorInfo>> moderators = SubForumDA.GetSubForumDA().GetModerators(this);

                for (int i = 0; i < moderators.Count; i++)
			    {
                    if (moderators[i].Key.Equals(mem))
                    {
                        return true;
                    }
			    }
            }
            return false;
        }

        public GThread GetLastMessage(Member member)
        {
            return SubForumDA.GetSubForumDA().GetLastMessage(this, member);
        }

        #endregion
    }
}